/*
 * GLThread.h
 *
 *  Created on: 27.11.2012
 *      Author: caffeine
 */

#ifndef GLTHREAD_H_
#define GLTHREAD_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/gl.h>
#include <GL/glx.h>

#define GLX_CONTEXT_MAJOR_VERSION_ARB       0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB       0x2092
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);

// Helper to check for extension string presence.  Adapted from:
//   http://www.opengl.org/resources/features/OGLextensions/
static bool isExtensionSupported(const char *extList, const char *extension)

{

  const char *start;
  const char *where, *terminator;

  /* Extension names should not have spaces. */
  where = strchr(extension, ' ');
  if ( where || *extension == '\0' )
    return false;

  /* It takes a bit of care to be fool-proof about parsing the
     OpenGL extensions string. Don't be fooled by sub-strings,
     etc. */
  for ( start = extList; ; ) {
    where = strstr( start, extension );

    if ( !where )
      break;

    terminator = where + strlen( extension );

    if ( where == start || *(where - 1) == ' ' )
      if ( *terminator == ' ' || *terminator == '\0' )
        return true;

    start = terminator;
  }

  return false;
}

static bool ctxErrorOccurred = false;


class GLSafeThread{
private:
	Display *display;
	GLXContext ctx;
	GLXPbuffer win;
	GLXFBConfig bestFbc;
	irr::video::IVideoDriver*driver;
public:
	GLSafeThread(irr::video::IVideoDriver*d){
		driver=d;
		display=(Display *)driver->getExposedVideoData().OpenGLLinux.X11Display;

			  static int visual_attribs[] = {None};

			  int fbcount;
			  GLXFBConfig *fbc = glXChooseFBConfig( display, DefaultScreen( display ),
			                                        visual_attribs, &fbcount );
			  if ( !fbc )
			  {
			    printf( "Failed to retrieve a framebuffer config\n" );
			    exit(1);
			  }

			  bestFbc = fbc[0];
			  XFree( fbc );

				static int pbufferAttribs[] =
				{
					GLX_PBUFFER_WIDTH, 2,
					GLX_PBUFFER_HEIGHT, 2,
					GLX_LARGEST_PBUFFER, False,
					None};
				win=glXCreatePbuffer(display,bestFbc,pbufferAttribs);

			  const char *glxExts = glXQueryExtensionsString(display,DefaultScreen(display));
			  glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
			  glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
			  ctx = 0;
			  ctxErrorOccurred = false;
			  if ( !isExtensionSupported( glxExts, "GLX_ARB_create_context" ) ||!glXCreateContextAttribsARB ){
			    ctx = glXCreateNewContext( display, bestFbc, GLX_RGBA_TYPE,(GLXContext)driver->getExposedVideoData().OpenGLLinux.X11Context, True );
			  }
			  else//If it does, try to get a GL 3.0 context!
			  {
			    int context_attribs[] =
			      {
			        GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
			        GLX_CONTEXT_MINOR_VERSION_ARB, 0,
			        None
			      };
			    ctx = glXCreateContextAttribsARB( display, bestFbc,(GLXContext)driver->getExposedVideoData().OpenGLLinux.X11Context,
			                                      True, context_attribs );

			    if ( !ctxErrorOccurred && ctx )
			      printf( "Created GL 3.0 context\n" );
			    else
			    {
			      context_attribs[1] = 1;
			      context_attribs[3] = 0;
			      ctxErrorOccurred = false;
			      ctx = glXCreateContextAttribsARB( display, bestFbc,(GLXContext)driver->getExposedVideoData().OpenGLLinux.X11Context,
			                                        True, context_attribs );
			    }
			  }

			  // Sync to ensure any errors generated are processed.
			  //XSync( display, False );

			  // Restore the original error handler
			  //XSetErrorHandler( oldHandler );

			  if ( ctxErrorOccurred || !ctx )
			  {
			    printf( "Failed to create an OpenGL context\n" );
			    exit(1);
			  }
			  glXMakeCurrent( display, win, ctx );
	}

	~GLSafeThread(){
		glXMakeCurrent( display, 0, 0 );
		glXDestroyContext( display, ctx );
		glXDestroyPbuffer( display, win );
	}
};


#endif /* GLTHREAD_H_ */
